package co.yixiang.config;

import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.Properties;

@Intercepts(
        {
                @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
                @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
        }
)
@Component
public class SelectSqlInterceptor implements Interceptor {
	private Field additionalParametersField;
	public SelectSqlInterceptor() throws NoSuchFieldException {
        additionalParametersField = BoundSql.class.getDeclaredField("additionalParameters");
//        boolean accessible = additionalParametersField.isAccessible();
        additionalParametersField.setAccessible(true);
    }
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement)args[0];
        Object parameter = args[1];
        RowBounds rowBounds = (RowBounds)args[2];
        ResultHandler resultHandler = (ResultHandler)args[3];
        Executor executor = (Executor)invocation.getTarget();
        CacheKey cacheKey;
        BoundSql boundSql;
        if (args.length == 4) {
            boundSql = ms.getBoundSql(parameter);
            cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);
        } else {
            cacheKey = (CacheKey)args[4];
            boundSql = (BoundSql)args[5];
        }
        String selectSql = boundSql.getSql();
        if(selectSql.indexOf("t.")> 10 && additionalParametersField!=null){
            //反射获取 BoundSql 中的 additionalParameters 属性
            Map<String, Object> additionalParameters = (Map<String, Object>) additionalParametersField.get(boundSql);
            selectSql = selectSql.replaceFirst("FROM ([^\\s]+)[\\s]+WHERE","from $1 t where");
            BoundSql selectBoundSql = new BoundSql(ms.getConfiguration(), selectSql, boundSql.getParameterMappings(), parameter);
            //当使用动态 SQL 时，可能会产生临时的参数，这些参数需要手动设置到新的 BoundSql 中
            for (String key : additionalParameters.keySet()) {
                selectBoundSql.setAdditionalParameter(key, additionalParameters.get(key));
            }
            return executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, selectBoundSql);
        }else{
            return executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);
        }

    }

    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

	public void setProperties(Properties properties) {
	}
}
